/*
 * com_wits_av_JniRecordCaster.cpp
 *
 *  Created on: 2018年9月2日
 *      Author: zhengboyuan
 */

#include "com_wits_av_JniRecordCaster.h"

#include <assert.h>
#include <stdio.h>
#include <string.h>

#include <android/native_window_jni.h>
#include <android/log.h>

#include "JniRecordCaster.h"
#include "JniHelper.h"
#include <vector>

#include "CLog.h"


JavaVM* g_Jvm = NULL;

jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
	__android_log_print(ANDROID_LOG_INFO, "jni", "--- JNI_OnLoad. JniMediaReader vm:%p", vm);

	g_Jvm = vm;

	JniRecordCaster::instance().setJvm(vm);

	return JNI_VERSION_1_4;
}

void JNI_OnUnload(JavaVM *vm, void *reserved)
{

}


jobject createJObject(JNIEnv * env, const av::MRecord& record)
{
	jclass cls = env->FindClass("com/wits/av/MRecord");
	jmethodID constructor = env->GetMethodID(cls, "<init>", "()V");
	jobject object = env->NewObject(cls, constructor);
	return object;
}

///////////////////////////////////////////////////////////////////

av::PsRecordCaster& getCaster()
{
	return JniRecordCaster::instance().getCaster();
}

///////////////////////////////////////////////////////////////////

/*
 * Class:     com_wits_av_JniRecordCaster
 * Method:    recordcaster_init
 * Signature: ()I
 */
JNIEXPORT jint JNICALL Java_com_wits_av_JniRecordCaster_recordcaster_1init
  (JNIEnv * env, jclass thiz)
{
	JniRecordCaster::init();
	return 0;
}

/*
 * Class:     com_wits_av_JniRecordCaster
 * Method:    recordcaster_quit
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_wits_av_JniRecordCaster_recordcaster_1quit
  (JNIEnv * env, jclass thiz)
{
	JniRecordCaster::quit();
}

/*
 * Class:     com_wits_av_JniRecordCaster
 * Method:    recordcaster_openRecordStore
 * Signature: (Ljava/lang/String;)Z
 */
JNIEXPORT jboolean JNICALL Java_com_wits_av_JniRecordCaster_recordcaster_1openRecordStore
  (JNIEnv * env, jclass thiz, jstring jdbpath)
{
	jni::UtfString dbpath(env, jdbpath);
	return JniRecordCaster::instance().open(dbpath.c_str());
}

/*
 * Class:     com_wits_av_JniRecordCaster
 * Method:    recordcaster_closeRecordStore
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_wits_av_JniRecordCaster_recordcaster_1closeRecordStore
  (JNIEnv * env, jclass thiz)
{
	JniRecordCaster::instance().releaseListener(env);

	JniRecordCaster::instance().close();
}

/*
 * Class:     com_wits_av_JniRecordCaster
 * Method:    recordcaster_findRecord
 * Signature: (Lcom/wits/av/MRecordQuery;I[Lcom/wits/av/MRecord;)I
 */
JNIEXPORT jint JNICALL Java_com_wits_av_JniRecordCaster_recordcaster_1findRecord
  (JNIEnv * env, jclass thiz, jobject jquery, jint joffset, jobjectArray jrecords)
{
	if (!jrecords)
	{
		return 0;
	}

	int length = env->GetArrayLength(jrecords);
	if (length <= 0)
	{
		return 0;
	}

	av::MRecordQuery query = av::MRecordQuery();

	jni::Object obj(env, "com/wits/av/MRecordQuery", jquery);
	obj.getInt("recordType", query.recordType);
	obj.getLong("fromTime", (jlong&)query.fromTime);
	obj.getLong("toTime", (jlong&)query.toTime);

	std::string device;
	obj.getString("device", device);
	std::string recorder;
	obj.getString("recorder", recorder);

	query.device = device.c_str();
	query.recorder = recorder.c_str();

	std::vector< av::MRecord > records;
	records.resize(128);

	CLog::info("findRecord. device: %s\n", device.c_str());
	int count = getCaster().findRecord(query, joffset, &(records[0]), length);

	for (int i = 0; i < count; ++ i)
	{
		av::MRecord& rec = records[i];
		jobject jrecord = createJObject(env, records[i]);

		jni::Object record(env, "com/wits/av/MRecord", jrecord);
		record.setInt("id", rec.id);
		record.setString("device", rec.device);
		record.setLong("startTime", rec.startTime);
		record.setLong("stopTime", rec.stopTime);
		record.setLong("filesize", rec.filesize);
		record.setInt("events", rec.events);
		record.setInt("type", rec.type);
		record.setInt("duration", rec.duration);
		record.setString("filename", rec.filename);
		record.setString("filepath", rec.filepath);
		record.setString("url", rec.url);
		record.setString("recorder", rec.recorder);
		record.setString("memo", rec.memo);

		env->SetObjectArrayElement(jrecords, i, jrecord);

		env->DeleteLocalRef(jrecord);
	}

	CLog::info("findRecord. return %d\n", count);

	return count;
}

/*
 * Class:     com_wits_av_JniRecordCaster
 * Method:    recordcaster_countRecord
 * Signature: (Lcom/wits/av/MRecordQuery;)I
 */
JNIEXPORT jint JNICALL Java_com_wits_av_JniRecordCaster_recordcaster_1countRecord
  (JNIEnv * env, jclass thiz, jobject jquery)
{
	av::MRecordQuery query = av::MRecordQuery();

	jni::Object obj(env, "com/wits/av/MRecordQuery", jquery);
	obj.getInt("recordType", query.recordType);
	obj.getLong("fromTime", (jlong&)query.fromTime);
	obj.getLong("toTime", (jlong&)query.toTime);

	std::string device;
	obj.getString("device", device);
	std::string recorder;
	obj.getString("recorder", recorder);

	query.device = device.c_str();
	query.recorder = recorder.c_str();

	return getCaster().countRecord(query);
}

/*
 * Class:     com_wits_av_JniRecordCaster
 * Method:    recordcaster_setEventCallback
 * Signature: (Lcom/wits/av/RecordCasterListener;)V
 */
JNIEXPORT void JNICALL Java_com_wits_av_JniRecordCaster_recordcaster_1setEventCallback
  (JNIEnv * env, jclass thiz, jobject jlistener)
{
	JniRecordCaster::instance().setListener(env, jlistener);
}

/*
 * Class:     com_wits_av_JniRecordCaster
 * Method:    recordcaster_openChannelFile
 * Signature: (Lcom/wits/av/RecordCasterTranport;[Lcom/wits/av/MRecord;ID)I
 */
JNIEXPORT jint JNICALL Java_com_wits_av_JniRecordCaster_recordcaster_1openChannelFile
  (JNIEnv * env, jclass thiz, jobject jtransport, jobjectArray jrecords, jint joffset, jdouble jscale)
{
	if (!jtransport || !jrecords)
	{
		return -1;
	}

	int length = env->GetArrayLength(jrecords);
	if (length <= 0)
	{
		return 0;
	}

	av::PsRecordCasterTransport transport = av::PsRecordCasterTransport();

	jni::Object obj(env, "com/wits/av/RecordCasterTranport", jtransport);
	obj.getInt("protocol", transport.protocol);
	obj.getInt("outPort", transport.outPort);
	obj.getInt("ssrc", (int&)transport.ssrc);
	obj.getInt("payload", transport.payload);
	obj.getInt("esMode", transport.esMode);

	std::vector< av::MRecord > records;

	for (int i = 0; i < length; ++ i)
	{
		av::MRecord record = av::MRecord();

		jobject element = env->GetObjectArrayElement(jrecords, i);
		if (!element)
		{
			continue;
		}

		jni::Object jrecord(env, "com/wits/av/MRecord", element);

		jrecord.getInt("id", record.id);
		jrecord.getString("device", record.device);
		jrecord.getLong("startTime", (int64_t&)record.startTime);
		jrecord.getLong("stopTime", (int64_t&)record.stopTime);
		jrecord.getLong("filesize", record.filesize);
		jrecord.getInt("events", record.events);
		jrecord.getInt("type", record.type);
		jrecord.getInt("duration", record.duration);
		jrecord.getString("filename", record.filename);
		jrecord.getString("filepath", record.filepath);
		jrecord.getString("url", record.url);
		jrecord.getString("recorder", record.recorder);
		jrecord.getString("memo", record.memo);

		records.push_back(record);
	}

	if (records.empty())
	{
		return -1;
	}

	return getCaster().openChannelFile(transport, &(records[0]), records.size(), joffset, jscale);
}

/*
 * Class:     com_wits_av_JniRecordCaster
 * Method:    recordcaster_openChannelTime
 * Signature: (Lcom/wits/av/RecordCasterTranport;Ljava/lang/String;JJD)I
 */
JNIEXPORT jint JNICALL Java_com_wits_av_JniRecordCaster_recordcaster_1openChannelTime
  (JNIEnv * env, jclass thiz, jobject jtransport, jstring jdevice, jlong jfromTime, jlong jtoTime, jdouble jscale)
{
	av::PsRecordCasterTransport transport = av::PsRecordCasterTransport();

	jni::Object obj(env, "com/wits/av/RecordCasterTranport", jtransport);
	obj.getInt("protocol", transport.protocol);
	obj.getInt("outPort", transport.outPort);
	obj.getInt("ssrc", (int&)transport.ssrc);
	obj.getInt("payload", transport.payload);
	obj.getInt("esMode", transport.esMode);

	jni::UtfString device(env, jdevice);

	return getCaster().openChannelTime(transport, device.c_str(), jfromTime, jtoTime, jscale);
}

/*
 * Class:     com_wits_av_JniRecordCaster
 * Method:    recordcaster_closeChannel
 * Signature: (I)V
 */
JNIEXPORT void JNICALL Java_com_wits_av_JniRecordCaster_recordcaster_1closeChannel
  (JNIEnv * env, jclass thiz, jint jhandle)
{
	getCaster().closeChannel(jhandle);
}

/*
 * Class:     com_wits_av_JniRecordCaster
 * Method:    recordcaster_addTarget
 * Signature: (ILjava/lang/String;I)Z
 */
JNIEXPORT jboolean JNICALL Java_com_wits_av_JniRecordCaster_recordcaster_1addTarget
  (JNIEnv * env, jclass thiz, jint jhandle, jstring jip, jint jport)
{
	jni::UtfString ip(env, jip);
	return getCaster().addTarget(jhandle, ip.c_str(),jport);
}

/*
 * Class:     com_wits_av_JniRecordCaster
 * Method:    recordcaster_removeTarget
 * Signature: (ILjava/lang/String;I)Z
 */
JNIEXPORT jboolean JNICALL Java_com_wits_av_JniRecordCaster_recordcaster_1removeTarget
  (JNIEnv * env, jclass thiz, jint jhandle, jstring jip, jint jport)
{
	jni::UtfString ip(env, jip);
	return getCaster().removeTarget(jhandle, ip.c_str(),jport);
}

/*
 * Class:     com_wits_av_JniRecordCaster
 * Method:    recordcaster_removeTargets
 * Signature: (I)V
 */
JNIEXPORT void JNICALL Java_com_wits_av_JniRecordCaster_recordcaster_1removeTargets
  (JNIEnv * env, jclass thiz, jint jhandle)
{
	getCaster().removeTargets(jhandle);
}


/*
 * Class:     com_wits_av_JniRecordCaster
 * Method:    recordcaster_setScale
 * Signature: (ID)Z
 */
JNIEXPORT jboolean JNICALL Java_com_wits_av_JniRecordCaster_recordcaster_1setScale
  (JNIEnv * env, jclass thiz, jint jhandle, jdouble jscale)
{
	return getCaster().setScale(jhandle, jscale);
}

/*
 * Class:     com_wits_av_JniRecordCaster
 * Method:    recordcaster_seek
 * Signature: (IJ)Z
 */
JNIEXPORT jboolean JNICALL Java_com_wits_av_JniRecordCaster_recordcaster_1seek
  (JNIEnv * env, jclass thiz, jint jhandle, jlong joffset)
{
	return getCaster().seek(jhandle, joffset);
}

/*
 * Class:     com_wits_av_JniRecordCaster
 * Method:    recordcaster_start
 * Signature: (I)Z
 */
JNIEXPORT jboolean JNICALL Java_com_wits_av_JniRecordCaster_recordcaster_1start
  (JNIEnv * env, jclass thiz, jint jhandle)
{
	return getCaster().startCast(jhandle);
}

/*
 * Class:     com_wits_av_JniRecordCaster
 * Method:    recordcaster_stop
 * Signature: (I)V
 */
JNIEXPORT void JNICALL Java_com_wits_av_JniRecordCaster_recordcaster_1stop
  (JNIEnv * env, jclass thiz, jint jhandle)
{
	getCaster().stopCast(jhandle);
}

/*
 * Class:     com_wits_av_JniRecordCaster
 * Method:    recordcaster_pause
 * Signature: (I)V
 */
JNIEXPORT void JNICALL Java_com_wits_av_JniRecordCaster_recordcaster_1pause
  (JNIEnv * env, jclass thiz, jint jhandle)
{
	getCaster().pauseCast(jhandle);
}


